package sdk.org.apache.shiro.utils;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.authc.pam.AuthenticationStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.authz.ModularRealmAuthorizer;
import org.apache.shiro.authz.permission.PermissionResolver;
import org.apache.shiro.authz.permission.WildcardPermissionResolver;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.util.Factory;
import org.apache.shiro.util.ThreadContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;

import com.titan.core.utils.file.ClassUtils;
import com.titan.core.utils.io.ConsoleUtils;
import com.titan.core.utils.io.ResourceUtils;
import com.titan.core.utils.object.VariantTwo;

import sdk.org.apache.shiro.domain.SysUserDomain;

public class ShiroUtils {
    private static final transient Logger log = LoggerFactory.getLogger(ShiroUtils.class);
    /**  加密算法 */
    public final static String HASH_ALGORITHM = "SHA-256";  // Md5Hash.ALGORITHM_NAME
    /**  循环次数 */
    public final static int HASH_ITERATIONS = 16;

    
    // 初始化SecurityManager
    // ShiroUtils.init("classpath:sdk/org/apache/shiro/A03认证器测试/ini/"+configFile);
    public static org.apache.shiro.mgt.SecurityManager init(final String iniResource) throws Exception {
        String iniResourcePath = null;
        if(iniResource.startsWith("classpath")) {
            iniResourcePath = iniResource;
        } else {
            Class<?> clazz = ClassUtils.parseCall(3);
            String pack = clazz.getPackage().getName().replace('.', '/');
            Resource resource = ResourceUtils.toResource("classpath:/"+pack+"/"+iniResource);
            if(resource.exists()) {
                iniResourcePath = resource.getFile().getPath();
            } else {
                resource = ResourceUtils.toResource("classpath*:/"+pack+"/**/"+iniResource);
                iniResourcePath = resource.getFile().getPath();
            }
        }
        
        //1、获取SecurityManager工厂，此处使用Ini配置文件初始化SecurityManager
        Factory<org.apache.shiro.mgt.SecurityManager> factory = new IniSecurityManagerFactory(iniResourcePath);
        
        //2、得到SecurityManager实例 并绑定给SecurityUtils
        org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);
        return securityManager;
    }
    public static org.apache.shiro.mgt.SecurityManager init(AuthenticationStrategy authenticationStrategy, PermissionResolver permissionResolver, Realm...realms) throws Exception {
        DefaultSecurityManager securityManager = new DefaultSecurityManager();

        // 设置authenticator
        ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator();
        authenticator.setAuthenticationStrategy(authenticationStrategy);
        securityManager.setAuthenticator(authenticator);
        
        // 设置authorizer
        ModularRealmAuthorizer authorizer = new ModularRealmAuthorizer();
        authorizer.setPermissionResolver(permissionResolver);
        securityManager.setAuthorizer(authorizer);
        
        if(realms==null) {
        } else if(realms.length==1) {
            securityManager.setRealm(realms[0]);
        } else {
            securityManager.setRealms(Arrays.asList(realms));
        }
        
        //将SecurityManager设置到SecurityUtils 方便全局使用
        SecurityUtils.setSecurityManager(securityManager);
        return securityManager;
    }
    public static org.apache.shiro.mgt.SecurityManager init(Realm...realms) throws Exception {
        return init(new AtLeastOneSuccessfulStrategy(), new WildcardPermissionResolver(), realms);
    }
    public static org.apache.shiro.mgt.SecurityManager init(VariantTwo<String,String>...usersAndPassword) throws Exception {
        SimpleAccountRealm realm = new SimpleAccountRealm();
        for (int i = 0; i < usersAndPassword.length; i++) {
            VariantTwo<String,String> user = usersAndPassword[i];
            realm.addAccount(user.getV1(), user.getV2());
        }
        JdbcRealm jdbcRealm = new JdbcRealm();
        return init(realm);
    }    
    
    public static String getUsername(AuthenticationToken token) {
        Object value = token.getPrincipal();
        //加这一步的目的是在Post请求的时候会先进认证，然后在到请求
        if (value == null) {
            return null;
        }
        //获取用户信息
        String username = value.toString();
        return username;
    }
    public static String getUsername(HttpServletRequest request) {
        Object object = SecurityUtils.getSubject().getPrincipal();
        if(object==null) {
            return null;
        } else if (object instanceof String) {
            return (String)object;
        } else if (object instanceof sdk.org.apache.shiro.domain.SysUserDomain) {
            SysUserDomain user = (SysUserDomain) object;
            return user.getLoginid();
        }
        return null;
    }
    public static String getUsername(PrincipalCollection principals, AuthorizingRealm realm) {
        if(principals==null || principals.isEmpty()) {
            return null;
        }
        Object primary = null;
        Collection thisPrincipals = principals.fromRealm(realm.getName());
        if (!CollectionUtils.isEmpty(thisPrincipals)) {
            primary = thisPrincipals.iterator().next();
        } else {
            primary = principals.getPrimaryPrincipal();
        }
        String username= (String)primary;
        return username;
    }
    public static String getPassword(AuthenticationToken token) {
        return new String((char[])token.getCredentials());        
    }
    public static String getPassword(String username, String password) {
        SimpleHash hash = new SimpleHash(
                HASH_ALGORITHM,
                ByteSource.Util.bytes(password),
                ByteSource.Util.bytes(username),
                HASH_ITERATIONS);
        String passwordNew = hash.toBase64();
        return passwordNew;
    }
    public static String sha256(String password, String salt) {
        return new SimpleHash(HASH_ALGORITHM, password, salt, HASH_ITERATIONS).toString();
    }

    
    
    // 登录
    // ShiroUtils.login("zhang", "123", true);
    public static Subject login(final String username, final String password, final boolean rememberMe) {
        //3、得到Subject及创建用户名/密码身份验证Token（即用户身份/凭证）
        Subject currentUser = SecurityUtils.getSubject();
        if (currentUser.isAuthenticated()) {
            log.info("User [" + currentUser.getPrincipal() + "] has logged in.");
        } else {
            UsernamePasswordToken token = new UsernamePasswordToken(username, password.toCharArray(), rememberMe, null);
            try {
                currentUser.login(token);
//                log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");
            } catch (UnknownAccountException uae) {
                log.info("There is no user with username of " + token.getPrincipal());
                throw uae;
            } catch (IncorrectCredentialsException ice) {
                log.info("Password for account " + token.getPrincipal() + " was incorrect!");
                throw ice;
            } catch (LockedAccountException lae) {
                log.info("The account for username " + token.getPrincipal() + " is locked.  " +
                        "Please contact your administrator to unlock it.");
                throw lae;
            }
            // ... catch more exceptions here (maybe custom ones specific to your application?
            catch (AuthenticationException ae) {
                //unexpected condition?  error?
                throw ae;
            }
        }
        return currentUser;
    }
    
    
    public static void logout() throws Exception {
        Subject currentUser = SecurityUtils.getSubject();
        try {
            currentUser.logout();
        } catch(org.apache.shiro.session.UnknownSessionException e) {
            // 一般在session超时时发生本异常。
        }
        // 退出时请解除绑定Subject到线程 否则对下次测试造成影响
        ThreadContext.unbindSubject();
    }
    
    
    public static void print() {
        Subject subject = SecurityUtils.getSubject();
        // 得到一个身份集合，其包含了Realm验证成功的身份信息
        PrincipalCollection principalCollection = subject.getPrincipals();
        if( principalCollection==null ) {
            System.out.println("获得的身份验证成功内容为null！");
            return;
        }
        List list = principalCollection.asList();
        System.out.println("获得的身份验证成功内容数量为："+list.size());
        for (int i = 0; i < list.size(); i++) {
            ConsoleUtils.log("["+i+"]", "list.get("+i+")", list.get(i));
        }
    }
}
